// test generics function that return generics struct
pub struct Optional<T> {
mut:
	value T
	some  bool
	typ   string
}

pub fn new_some<T, B>(value T, b B) Optional<T> {
	return {
		value: value
		some: true
		typ: typeof(b).name
	}
}

pub fn some<T>(opt Optional<T>) bool {
	return opt.some
}

pub fn get_value<T>(opt Optional<T>) T {
	return opt.value
}

pub fn get_typ<T>(opt Optional<T>) string {
	return opt.typ
}

pub fn set<T, B>(mut opt Optional<T>, value T, b B) {
	opt.value = value
	opt.some = true
	opt.typ = typeof(b).name
}

fn test_inconsistent_types_generics_fn_return_generics_struct() {
	mut o := new_some<int, string>(23, 'aaa')
	println(some<int>(o))
	assert some<int>(o) == true

	println(get_value<int>(o))
	assert get_value<int>(o) == 23

	set<int, string>(mut o, 42, 'aaa')
	println(get_value<int>(o))
	assert get_value<int>(o) == 42

	println(get_typ<int>(o))
	assert get_typ<int>(o) == 'string'
}

// test generics method that return generics struct
pub struct Foo {
	foo int
}

pub fn (f Foo) new_some<T, B>(value T, b B) Optional<T> {
	return {
		value: value
		some: true
		typ: typeof(b).name
	}
}

pub fn (f Foo) some<T>(opt Optional<T>) bool {
	return opt.some
}

pub fn (f Foo) get_value<T>(opt Optional<T>) T {
	return opt.value
}

pub fn (f Foo) get_typ<T>(opt Optional<T>) string {
	return opt.typ
}

pub fn (f Foo) set<T, B>(mut opt Optional<T>, value T, b B) {
	opt.value = value
	opt.some = true
	opt.typ = typeof(b).name
}

fn test_inconstent_types_generics_method_return_generics_struct() {
	foo := Foo{}
	mut o := foo.new_some<int, string>(23, 'aaa')
	println(foo.some<int>(o))
	assert foo.some<int>(o) == true

	println(foo.get_value<int>(o))
	assert foo.get_value<int>(o) == 23

	foo.set<int, string>(mut o, 42, 'aaa')
	println(foo.get_value<int>(o))
	assert foo.get_value<int>(o) == 42

	println(foo.get_typ<int>(o))
	assert foo.get_typ<int>(o) == 'string'
}
